package happychat;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.Date;

public class GUIChat extends Frame {
	// 继承Frame，拿到其所有方法
	private TextField tf;
	private Button send;
	private Button log;
	private Button clear;

	private Button send_files;
	private Button settings;
	private Button easy;

	private TextArea viewText;
	private TextArea sendText;
	private DatagramSocket socket;
	private BufferedWriter bw;

	public GUIChat() {
		init();
		southPanel();
		centerPannel();
		event();
	}

	public void event() {
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				try {
					socket.close();
					bw.close();
				} catch (IOException e1) {
					// TODO 自动生成的 catch 块
					e1.printStackTrace();
				}
				System.exit(0);
			}
		});// 退出jvm

		// 为发送按钮添加动作监听
		send.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					send();

				} catch (IOException e1) {
					// TODO 自动生成的 catch 块
					e1.printStackTrace();
				} // 调用send方法
			}
		});

		log.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					logFile();
				} catch (IOException e1) {
					// TODO 自动生成的 catch 块
					e1.printStackTrace();
				}
			}

		});

		clear.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				viewText.setText("");
			}
		});


		sendText.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent e) {// 键盘监听
				if (e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) {
					try {
						send();

					} catch (IOException e1) {
						// TODO 自动生成的 catch 块
						e1.printStackTrace();
					}
				}

			}
		});


		send_files.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					openChooser();
				} catch (Exception e1) {
					// TODO 自动生成的 catch 块
					e1.printStackTrace();
				} // 调用send方法
			}
		});
		settings.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					ziYuan();
				} catch (Exception e1) {
					// TODO 自动生成的 catch 块
					e1.printStackTrace();
				} // 调用send方法
			}
		});

	}

	private void openChooser() throws IOException {
		// Runtime.getRuntime().exec("explorer.exe / select," + "D:\\io测试专用文件夹");
		JFileChooser fc = new JFileChooser();
		fc.setFileSelectionMode(JFileChooser.OPEN_DIALOG);
		fc.showOpenDialog(null);
		File f = fc.getSelectedFile();
		if (f != null) {
			System.out.println(f.getPath());
		}
	}

	private void ziYuan() throws IOException {
		Runtime.getRuntime().exec("explorer.exe / select," + "C:\\Users\\李博衍\\IdeaProjects\\Gui\\src");
	}



	private void shake() {
		// 获取位置
		int x = this.getLocation().x;
		int y = this.getLocation().y;// 获取横纵坐标
		for (int i = 0; i < 10; i++) {
			try {
				this.setLocation(x + 20, y);
				Thread.sleep(20);
				this.setLocation(x - 20, y);
				Thread.sleep(20);
				this.setLocation(x + 20, y);
				Thread.sleep(20);
				this.setLocation(x - 20, y);
				Thread.sleep(20);
				this.setLocation(x, y);
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}

	}

	private void logFile() throws IOException {
		// 窗口一产生就创建文件
		bw.flush();// 点记录就刷新缓冲区
		// 用内存缓冲流显示记录
		FileInputStream fis = new FileInputStream("config.txt");
		ByteArrayOutputStream baos = new ByteArrayOutputStream();// 在内存中创建缓冲区
		int len;
		byte[] arr = new byte[8192];
		while ((len = fis.read(arr)) != -1) {
			baos.write(arr, 0, len);
		}
		String str = baos.toString();// 内存中的数据转换为字符串
		viewText.setText(str);
		fis.close();

	}

	private void send(byte[] arr, String ip) throws IOException {
		DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9999);// 数据，长度，ip地址，端口号
		socket.send(packet);// 发送数据
	}

	private void send() throws IOException {
		String message = sendText.getText();// 获取发送区域的内容
		String ip = tf.getText();// 获取要发送目标的ip地址
		ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;// 如果ip为空，则认为是255,255,255,255,即所有ip

		send(message.getBytes(), ip);

		String time = getCurrentTime();// 调用获取当前时间的方法
		String str = time + " 我对" + ip + "说: " + message + "\r\n";
		viewText.append(str);// 将信息添加到显示区域中
		bw.write(str);// 将信息写到记录文件中
		sendText.setText("");// 清空输入区域

	}

	public String getCurrentTime() {
		Date d = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/HH:mm:ss");
		return sdf.format(d);// 将时间格式化并返回
	}

	public void centerPannel() {
		// TODO 自动生成的方法存根
		Panel center = new Panel();// 创建中间Pannel
		viewText = new TextArea();
		sendText = new TextArea(5, 60);
		// 注意Pannel默认是流式布局，而我们想让两个文本区一上一下放置
		// 故不能使用流式布局，而应该使用边界布局
		center.setLayout(new BorderLayout()); // 设置为边界布局管理器
		center.add(sendText, BorderLayout.SOUTH);
		center.add(viewText, BorderLayout.CENTER);

		viewText.setEditable(false);
		viewText.setBackground(Color.decode("#E4E9F7"));
		sendText.setFont(new Font("xxx", Font.PLAIN, 20));
		sendText.setBackground(Color.decode("#E4E9F7"));//"#E8F2FE"
		viewText.setFont(new Font("xxx", Font.PLAIN, 20));

		this.add(center, BorderLayout.CENTER);// 设置显示区为不可编辑

	}

	public void init() {
		// 初始化
		this.setLocation(500, 50);
		this.setSize(800, 600);
		this.setTitle("MANTONG  v1.0");
		new Receive().start();

		// 设置窗体图标
		Image img0 = new ImageIcon("mao.png").getImage();
		this.setIconImage(img0);

		// 设置窗体大小不能改变
		this.setResizable(false);
		try {
			socket = new DatagramSocket();
			bw = new BufferedWriter(new FileWriter("config.txt", true));// 在尾部追加

		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		this.setVisible(true);
	}

	// 用内部类做了一个接收端，提高viewText、currentTime的复用
	private class Receive extends Thread {// 接收和发送需要同时执行，所以要定义成多线程的
		public void run() {
			try {
				DatagramSocket socket = new DatagramSocket(9999);
				DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
				while (true) {
					socket.receive(packet);// 接收信息
					byte[] arr = packet.getData();// 获取字节数据
					int len = packet.getLength();// 获取有效的字节数据
					if (arr[0] == -1 && len == 1) {
						shake();
						// 满足条件就调用shake,震动
						continue;// 都震动了，后面就不用执行了，直接跳过本次循环
					}
					String message = new String(arr, 0, len);// 转换成字符串
					String time = getCurrentTime();// 获取当前时间
					String ip = packet.getAddress().getHostAddress();// 获取ip
					String str = time + " " + ip + "对我说: " + message + "\r\n";
					viewText.append(str);
					bw.write(str);

				}

			} catch (Exception e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
	}

	public void southPanel() {
		Panel south = new Panel();// 创建南边panel
		south.setBackground(Color.decode("#E4E9F7"));
		tf = new TextField(18);
		tf.setText("127.0.0.1");
		send = new Button("Send");
		log = new Button("Chat record");
		clear = new Button("Clear the screen");

		send_files = new Button("File transfer");
		settings = new Button("Individualization");
		easy = new Button("Shortcut key");

		tf.setFont(new Font("xxx", Font.PLAIN, 20));
		send.setFont(new Font("宋体", Font.BOLD, 20));
		log.setFont(new Font("xxx", Font.PLAIN, 20));
		clear.setFont(new Font("xxx", Font.PLAIN, 20));

		send_files.setFont(new Font("xxx", Font.PLAIN, 20));
		settings.setFont(new Font("xxx", Font.PLAIN, 20));


		south.add(tf);
		south.add(send);
		south.add(log);
		south.add(clear);

		south.add(send_files);
		south.add(settings);// 默认流式布局

		this.add(south, BorderLayout.SOUTH);// 使用边界布局管理器将Pannel放在Frame的南边
	}

	public static void main(String arg[]) {
		new GUIChat();
	}
}
